import { Application } from "egg";
import CodoBase from "../CodoBase";
import { Weaver } from "./type";
import CodoError from "../CodoError";
import * as crypto from "crypto";

export class WeaverAuth extends CodoBase {
	constructor(app: Application, private config: Weaver.Config) {
		super(app);
	}

	/** 向OA发送许可证信息进行注册认证 注意仅第一次注册，后续不能重复，否则导致以前的加密失效。新版e9已修正，重复调用返回相同公钥。
	 * - https://e-cloudstore.com/doc.html?appId=af09c25938714c26b9736f535ca20fc9#<strong>3.1、第一步：向OA系统发送许可证信息进行注册认证（只需要注册一次即可，后面多次注册会更新密钥导致解密失败，最新版本的ecology已经隔离出注册和更新接口）</strong>
	 */
	async register() {
		const url = `${this.config.baseUrl}/api/ec/dev/auth/regist`;
		const res = await this.app.curl(url, {
			method: "POST",
			headers: {
				appid: this.config.appid,
				// cpk: qs.escape(this.config.ehrPublicKey),
				// cpk:  this.config.ehrPublicKey.split("\n")[1],
				cpk: "123",
			},
			contentType: "application/x-www-form-urlencoded; charset=utf-8",
			dataType: "text",
		});
		const body = JSON.parse(res.data) as Weaver.RegisterResponse;
		if (body.code != 0) throw new CodoError(body.code + body.msg);
		return body;
	}

	/** 通过获取的秘钥申请token */
	async applyToken() {
		const url = `${this.config.baseUrl}/api/ec/dev/auth/applytoken`;

		const secret = this.config.ecologySecret;
		const encryptedSecret = WeaverAuth.publicKeyEncrypt(this.config.ecologyPublicKey, secret);

		const res = await this.app.curl(url, {
			method: "POST",
			headers: {
				appid: this.config.appid,
				secret: encryptedSecret, // 使用泛微公钥加密秘钥后的密文。
			},
			contentType: "application/x-www-form-urlencoded; charset=utf-8",
			dataType: "text",
		});

		const body = JSON.parse(res.data) as Weaver.TokenResponse;
		if (body.code != 0) throw new CodoError(body.code + body.msg);
		return body;
	}

	/** 获取token
	 * -  默认token有效期30min，可缓存使用 ，外部一般调用本方法即可
	 * */
	async getToken() {
		const cacheKey = `codo:weaver:ecology9:token:${this.config.appid}`;
		const cache = await this.app.redis.get(cacheKey);
		if (cache) return cache;
		const token = await this.applyToken();
		await this.app.redis.set(cacheKey, token.token, "EX", 29 * 60);
		return token.token;
	}

	/** 使用公钥加密数据 */
	static publicKeyEncrypt(publicKey: string, data: string) {
		if (!publicKey.startsWith("-----BEGIN PUBLIC KEY-----")) {
			publicKey = `-----BEGIN PUBLIC KEY-----\n${publicKey}\n-----END PUBLIC KEY-----`;
		}

		const encryptedSecret = crypto.publicEncrypt(
			{
				key: publicKey,
				padding: crypto.constants.RSA_PKCS1_PADDING,
			},
			Buffer.from(data, "utf-8")
		);
		return encryptedSecret.toString("base64");
	}
}
